package com.cloud.flowable.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.BetweenFormatter;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cloud.common.constant.ProcessConstants;
import com.cloud.common.constants.FlowTaskConstants;
import com.cloud.common.enums.ProcessStatus;
import com.cloud.common.utils.FlowableUtils;
import com.cloud.common.utils.BpmnModelUtils;
import com.cloud.common.utils.ProcessQueryUtils;
import com.cloud.common.utils.FlowTaskUtils;
import com.cloud.entity.SysDept;
import com.cloud.entity.SysRole;
import com.cloud.entity.SysUser;
import com.cloud.exception.CustomException;
import com.cloud.flowable.entity.WfCategory;
import com.cloud.flowable.entity.WfDeployForm;
import com.cloud.flowable.entity.bo.ProcessPage;
import com.cloud.entity.vo.TaskParam;
import com.cloud.flowable.entity.vo.*;
import com.cloud.flowable.mapper.WfCategoryMapper;
import com.cloud.flowable.mapper.WfDeployFormMapper;
import com.cloud.flowable.service.IWfProcessService;
import com.cloud.flowable.service.IWfTaskService;
import com.cloud.service.FeignSystemService;
import com.cloud.utils.DateUtils;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.constants.BpmnXMLConstants;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.StartEvent;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricActivityInstanceQuery;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.repository.ProcessDefinitionQuery;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.task.Comment;
import org.flowable.identitylink.api.history.HistoricIdentityLink;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.api.history.HistoricTaskInstanceQuery;
import org.flowable.variable.api.history.HistoricVariableInstance;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class WfProcessServiceImpl extends FlowServiceFactory implements IWfProcessService {
    @Resource
    private IWfTaskService wfTaskService;
    @Resource
    private WfDeployFormMapper deployFormMapper;
    @Resource
    private FeignSystemService feignSystemService;
    @Resource
    private WfCategoryMapper categoryMapper;

    /**
     * 流程定义列表
     *
     * @return 流程定义分页列表数据
     */
    @Override
    public Page<WfDefinitionVo> selectStartProcessPage(ProcessPage procPage) {
        Page<WfDefinitionVo> defPage = new Page<>();
        // 流程定义列表数据查询
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery()
                .latestVersion().active().orderByProcessDefinitionKey().asc();
        // 构建搜索条件
        ProcessQueryUtils.buildProcessSearch(processDefinitionQuery, procPage);
        defPage.setTotal(processDefinitionQuery.count());
        if (processDefinitionQuery.count() <= 0) {
            defPage.setRecords(new ArrayList<>());
            return defPage;
        }
        List<WfDefinitionVo> definitionVoList = new ArrayList<>();
        int offset = procPage.getPageSize() * (procPage.getPageNum() - 1);
        List<ProcessDefinition> definitionList = processDefinitionQuery.listPage(offset, procPage.getPageSize());
        for (ProcessDefinition processDefinition : definitionList) {
            String deploymentId = processDefinition.getDeploymentId();
            Deployment deployment = repositoryService.createDeploymentQuery().deploymentId(deploymentId).singleResult();
            WfDefinitionVo vo = new WfDefinitionVo();
            vo.setDefinitionId(processDefinition.getId());
            vo.setProcessKey(processDefinition.getKey());
            vo.setProcessName(processDefinition.getName());
            vo.setVersion(processDefinition.getVersion());
            vo.setDeploymentId(processDefinition.getDeploymentId());
            vo.setSuspended(processDefinition.isSuspended());
            // 流程定义时间
            vo.setCategory(deployment.getCategory());
            WfCategory wfCategory = categoryMapper.getCategoryByCode(deployment.getCategory());
            vo.setCategoryName(wfCategory.getCategoryName());
            vo.setDeploymentTime(deployment.getDeploymentTime());
            definitionVoList.add(vo);
        }
        defPage.setRecords(definitionVoList);
        return defPage;
    }

    /**
     * 查询可发起流程列表
     */
    @Override
    public List<WfDefinitionVo> selectStartProcessList(ProcessPage procPage) {
        // 流程定义列表数据查询
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery()
                .latestVersion().active().orderByProcessDefinitionKey().asc();
        // 构建搜索条件
        ProcessQueryUtils.buildProcessSearch(processDefinitionQuery, procPage);
        List<WfDefinitionVo> definitionVoList = new ArrayList<>();
        List<ProcessDefinition> definitionList = processDefinitionQuery.list();
        for (ProcessDefinition processDefinition : definitionList) {
            String deploymentId = processDefinition.getDeploymentId();
            Deployment deployment = repositoryService.createDeploymentQuery().deploymentId(deploymentId).singleResult();
            WfDefinitionVo vo = new WfDefinitionVo();
            vo.setDefinitionId(processDefinition.getId());
            vo.setProcessKey(processDefinition.getKey());
            vo.setProcessName(processDefinition.getName());
            vo.setVersion(processDefinition.getVersion());
            vo.setDeploymentId(processDefinition.getDeploymentId());
            vo.setSuspended(processDefinition.isSuspended());
            // 流程定义时间
            vo.setCategory(deployment.getCategory());
            vo.setDeploymentTime(deployment.getDeploymentTime());
            definitionVoList.add(vo);
        }
        return definitionVoList;
    }

    /**
     * 查询我的流程列表
     */
    @Override
    public Page<WfTaskVo> selectOwnProcessPage(ProcessPage procPage) {
        Page<WfTaskVo> taskPage = new Page<>();
        HistoricProcessInstanceQuery histProcInstanceQuery = historyService.createHistoricProcessInstanceQuery()
                .startedBy(FlowTaskUtils.getUserId()).orderByProcessInstanceStartTime().desc();
        // 构建搜索条件
        ProcessQueryUtils.buildProcessSearch(histProcInstanceQuery, procPage);
        taskPage.setTotal(histProcInstanceQuery.count());
        if (histProcInstanceQuery.count() <= 0) {
            taskPage.setRecords(new ArrayList<>());
            return taskPage;
        }
        int offset = procPage.getPageSize() * (procPage.getPageNum() - 1);
        List<HistoricProcessInstance> histProcInstances = histProcInstanceQuery
                .listPage(offset, procPage.getPageSize());
        List<WfTaskVo> taskVoList = new ArrayList<>();
        for (HistoricProcessInstance hisIns : histProcInstances) {
            WfTaskVo taskVo = new WfTaskVo();
            // 获取流程状态
            HistoricVariableInstance processStatusVariable = historyService.createHistoricVariableInstanceQuery()
                    .processInstanceId(hisIns.getId()).variableName(ProcessConstants.PROCESS_STATUS_KEY).singleResult();
            String processStatus = null;
            if (ObjectUtil.isNotNull(processStatusVariable)) {
                processStatus = Convert.toStr(processStatusVariable.getValue());
            }
            // 兼容旧流程
            if (processStatus == null) {
                processStatus = ObjectUtil.isNull(hisIns.getEndTime()) ?
                        ProcessStatus.RUNNING.getStatus() : ProcessStatus.COMPLETED.getStatus();
            }
            taskVo.setProcessStatus(processStatus);
            taskVo.setCreateTime(hisIns.getStartTime());
            taskVo.setFinishTime(hisIns.getEndTime());
            taskVo.setProcInsId(hisIns.getId());
            // 计算耗时
            if (Objects.nonNull(hisIns.getEndTime())) {
                taskVo.setDuration(DateUtils.getDatePoor(hisIns.getEndTime(), hisIns.getStartTime()));
            } else {
                taskVo.setDuration(DateUtils.getDatePoor(DateUtils.getNowDate(), hisIns.getStartTime()));
            }
            // 流程部署实例信息
            Deployment deployment = repositoryService.createDeploymentQuery()
                    .deploymentId(hisIns.getDeploymentId()).singleResult();
            taskVo.setDeployId(hisIns.getDeploymentId());
            taskVo.setProcDefId(hisIns.getProcessDefinitionId());
            taskVo.setProcDefName(hisIns.getProcessDefinitionName());
            taskVo.setProcDefVersion(hisIns.getProcessDefinitionVersion());
            taskVo.setCategory(deployment.getCategory());
            // 当前所处流程
            List<Task> taskList = taskService.createTaskQuery()
                    .processInstanceId(hisIns.getId()).includeIdentityLinks().list();
            if (CollUtil.isNotEmpty(taskList)) {
                taskVo.setTaskName(taskList.stream().map(Task::getName).filter(StringUtils::isNotEmpty)
                        .collect(Collectors.joining(",")));
            } else {
                taskVo.setTaskName("结束");
            }
            taskVoList.add(taskVo);
        }
        taskPage.setRecords(taskVoList);
        return taskPage;
    }

    /**
     * 查询我的流程列表
     */
    @Override
    public List<WfTaskVo> selectOwnProcessList(ProcessPage procPage) {
        HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery()
                .startedBy(FlowTaskUtils.getUserId()).orderByProcessInstanceStartTime().desc();
        // 构建搜索条件
        ProcessQueryUtils.buildProcessSearch(historicProcessInstanceQuery, procPage);
        List<HistoricProcessInstance> historicProcessInstances = historicProcessInstanceQuery.list();
        List<WfTaskVo> taskVoList = new ArrayList<>();
        for (HistoricProcessInstance hisIns : historicProcessInstances) {
            WfTaskVo taskVo = new WfTaskVo();
            taskVo.setCreateTime(hisIns.getStartTime());
            taskVo.setFinishTime(hisIns.getEndTime());
            taskVo.setProcInsId(hisIns.getId());
            // 计算耗时
            if (Objects.nonNull(hisIns.getEndTime())) {
                taskVo.setDuration(DateUtils.getDatePoor(hisIns.getEndTime(), hisIns.getStartTime()));
            } else {
                taskVo.setDuration(DateUtils.getDatePoor(DateUtils.getNowDate(), hisIns.getStartTime()));
            }
            // 流程部署实例信息
            Deployment deployment = repositoryService.createDeploymentQuery()
                    .deploymentId(hisIns.getDeploymentId()).singleResult();
            taskVo.setDeployId(hisIns.getDeploymentId());
            taskVo.setProcDefId(hisIns.getProcessDefinitionId());
            taskVo.setProcDefName(hisIns.getProcessDefinitionName());
            taskVo.setProcDefVersion(hisIns.getProcessDefinitionVersion());
            taskVo.setCategory(deployment.getCategory());
            // 当前所处流程
            List<Task> taskList = taskService.createTaskQuery()
                    .processInstanceId(hisIns.getId()).includeIdentityLinks().list();
            if (CollUtil.isNotEmpty(taskList)) {
                taskVo.setTaskName(taskList.stream().map(Task::getName)
                        .filter(StringUtils::isNotEmpty).collect(Collectors.joining(",")));
            }
            taskVoList.add(taskVo);
        }
        return taskVoList;
    }

    /**
     * 查询代办任务列表
     */
    @Override
    public Page<WfTaskVo> selectTodoProcessPage(ProcessPage procPage) {
        Page<WfTaskVo> taskPage = new Page<>();
        TaskQuery taskQuery = taskService.createTaskQuery()
                .active().includeProcessVariables().taskCandidateOrAssigned(FlowTaskUtils.getUserId())
                .taskCandidateGroupIn(FlowTaskUtils.getCandidateGroup()).orderByTaskCreateTime().desc();
        // 构建搜索条件
        ProcessQueryUtils.buildProcessSearch(taskQuery, procPage);
        taskPage.setTotal(taskQuery.count());
        if (taskQuery.count() <= 0) {
            taskPage.setRecords(new ArrayList<>());
            return taskPage;
        }
        int offset = procPage.getPageSize() * (procPage.getPageNum() - 1);
        List<Task> taskList = taskQuery.listPage(offset, procPage.getPageSize());
        List<WfTaskVo> flowList = new ArrayList<>();
        for (Task task : taskList) {
            WfTaskVo flowTask = new WfTaskVo();
            // 当前流程信息
            flowTask.setTaskId(task.getId());
            flowTask.setTaskDefKey(task.getTaskDefinitionKey());
            flowTask.setCreateTime(task.getCreateTime());
            flowTask.setProcDefId(task.getProcessDefinitionId());
            flowTask.setTaskName(task.getName());
            // 流程定义信息
            ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
                    .processDefinitionId(task.getProcessDefinitionId()).singleResult();
            flowTask.setDeployId(pd.getDeploymentId());
            flowTask.setProcDefName(pd.getName());
            flowTask.setProcDefVersion(pd.getVersion());
            flowTask.setProcInsId(task.getProcessInstanceId());
            // 流程发起人信息
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                    .processInstanceId(task.getProcessInstanceId()).singleResult();
            Long userId = Long.parseLong(historicProcessInstance.getStartUserId());
            flowTask.setStartUserId(userId);
            SysUser userInfo = feignSystemService.selectInUserInfo(userId).getData();
            if (userInfo != null) {
                flowTask.setStartUserName(userInfo.getNickName());
            }
            // 流程变量
//            flowTask.setProcVars(task.getProcessVariables());
            flowList.add(flowTask);
        }
        taskPage.setRecords(flowList);
        return taskPage;
    }

    /**
     * 查询代办任务列表
     */
    @Override
    public List<WfTaskVo> selectTodoProcessList(ProcessPage procPage) {
        TaskQuery taskQuery = taskService.createTaskQuery().active().includeProcessVariables()
                .taskCandidateOrAssigned(FlowTaskUtils.getUserId()).taskCandidateGroupIn(FlowTaskUtils.getCandidateGroup())
                .orderByTaskCreateTime().desc();
        // 构建搜索条件
        ProcessQueryUtils.buildProcessSearch(taskQuery, procPage);
        List<Task> taskList = taskQuery.list();
        List<WfTaskVo> taskVoList = new ArrayList<>();
        for (Task task : taskList) {
            WfTaskVo taskVo = new WfTaskVo();
            // 当前流程信息
            taskVo.setTaskId(task.getId());
            taskVo.setTaskDefKey(task.getTaskDefinitionKey());
            taskVo.setCreateTime(task.getCreateTime());
            taskVo.setProcDefId(task.getProcessDefinitionId());
            taskVo.setTaskName(task.getName());
            // 流程定义信息
            ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
                    .processDefinitionId(task.getProcessDefinitionId()).singleResult();
            taskVo.setDeployId(pd.getDeploymentId());
            taskVo.setProcDefName(pd.getName());
            taskVo.setProcDefVersion(pd.getVersion());
            taskVo.setProcInsId(task.getProcessInstanceId());
            // 流程发起人信息
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                    .processInstanceId(task.getProcessInstanceId()).singleResult();
            Long userId = Long.parseLong(historicProcessInstance.getStartUserId());
            String nickName = null;
            taskVo.setStartUserId(userId);
            taskVo.setStartUserName(nickName);
            taskVoList.add(taskVo);
        }
        return taskVoList;
    }

    /**
     * 查询待签任务列表
     */
    @Override
    public Page<WfTaskVo> selectClaimProcessPage(ProcessPage procPage) {
        Page<WfTaskVo> taskPage = new Page<>();
        TaskQuery taskQuery = taskService.createTaskQuery().active().includeProcessVariables()
                .taskCandidateUser(FlowTaskUtils.getUserId()).taskCandidateGroupIn(FlowTaskUtils.getCandidateGroup())
                .orderByTaskCreateTime().desc();
        // 构建搜索条件
        ProcessQueryUtils.buildProcessSearch(taskQuery, procPage);
        taskPage.setTotal(taskQuery.count());
        if (taskQuery.count() <= 0) {
            taskPage.setRecords(new ArrayList<>());
            return taskPage;
        }
        int offset = procPage.getPageSize() * (procPage.getPageNum() - 1);
        List<Task> taskList = taskQuery.listPage(offset, procPage.getPageSize());
        List<WfTaskVo> flowList = new ArrayList<>();
        for (Task task : taskList) {
            WfTaskVo flowTask = new WfTaskVo();
            // 当前流程信息
            flowTask.setTaskId(task.getId());
            flowTask.setTaskDefKey(task.getTaskDefinitionKey());
            flowTask.setCreateTime(task.getCreateTime());
            flowTask.setProcDefId(task.getProcessDefinitionId());
            flowTask.setTaskName(task.getName());
            // 流程定义信息
            ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
                    .processDefinitionId(task.getProcessDefinitionId()).singleResult();
            flowTask.setDeployId(pd.getDeploymentId());
            flowTask.setProcDefName(pd.getName());
            flowTask.setProcDefVersion(pd.getVersion());
            flowTask.setProcInsId(task.getProcessInstanceId());
            // 流程发起人信息
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                    .processInstanceId(task.getProcessInstanceId())
                    .singleResult();
            Long userId = Long.parseLong(historicProcessInstance.getStartUserId());
            flowTask.setStartUserId(userId);
            SysUser userInfo = feignSystemService.selectInUserInfo(userId).getData();
            if (userInfo != null) {
                flowTask.setStartUserName(userInfo.getNickName());
            }
            flowList.add(flowTask);
        }
        taskPage.setRecords(flowList);
        return taskPage;
    }

    /**
     * 查询待签任务列表
     */
    @Override
    public List<WfTaskVo> selectClaimProcessList(ProcessPage procPage) {
        TaskQuery taskQuery = taskService.createTaskQuery().active().includeProcessVariables()
                .taskCandidateUser(FlowTaskUtils.getUserId()).taskCandidateGroupIn(FlowTaskUtils.getCandidateGroup())
                .orderByTaskCreateTime().desc();
        // 构建搜索条件
        ProcessQueryUtils.buildProcessSearch(taskQuery, procPage);
        List<Task> taskList = taskQuery.list();
        List<WfTaskVo> flowVoList = new ArrayList<>();
        for (Task task : taskList) {
            WfTaskVo flowTask = new WfTaskVo();
            // 当前流程信息
            flowTask.setTaskId(task.getId());
            flowTask.setTaskDefKey(task.getTaskDefinitionKey());
            flowTask.setCreateTime(task.getCreateTime());
            flowTask.setProcDefId(task.getProcessDefinitionId());
            flowTask.setTaskName(task.getName());
            // 流程定义信息
            ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
                    .processDefinitionId(task.getProcessDefinitionId()).singleResult();
            flowTask.setDeployId(pd.getDeploymentId());
            flowTask.setProcDefName(pd.getName());
            flowTask.setProcDefVersion(pd.getVersion());
            flowTask.setProcInsId(task.getProcessInstanceId());
            // 流程发起人信息
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                    .processInstanceId(task.getProcessInstanceId()).singleResult();
            Long userId = Long.parseLong(historicProcessInstance.getStartUserId());
            flowTask.setStartUserId(userId);
            SysUser userInfo = feignSystemService.selectInUserInfo(userId).getData();
            if (userInfo != null) {
                flowTask.setStartUserName(userInfo.getNickName());
            }
            flowVoList.add(flowTask);
        }
        return flowVoList;
    }

    /**
     * 查询已办任务列表
     */
    @Override
    public Page<WfTaskVo> selectFinishedProcessPage(ProcessPage procPage) {
        Page<WfTaskVo> taskPage = new Page<>();
        HistoricTaskInstanceQuery taskInstanceQuery = historyService.createHistoricTaskInstanceQuery()
                .includeProcessVariables().finished().taskAssignee(FlowTaskUtils.getUserId())
                .orderByHistoricTaskInstanceEndTime().desc();
        // 构建搜索条件
        ProcessQueryUtils.buildProcessSearch(taskInstanceQuery, procPage);
        taskPage.setTotal(taskInstanceQuery.count());
        if (taskInstanceQuery.count() <= 0) {
            taskPage.setRecords(new ArrayList<>());
            return taskPage;
        }
        int offset = procPage.getPageSize() * (procPage.getPageNum() - 1);
        List<HistoricTaskInstance> historicTaskInstanceList = taskInstanceQuery.listPage(offset, procPage.getPageSize());
        List<WfTaskVo> hisTaskList = new ArrayList<>();
        for (HistoricTaskInstance histTask : historicTaskInstanceList) {
            WfTaskVo flowTask = new WfTaskVo();
            // 当前流程信息
            flowTask.setTaskId(histTask.getId());
            // 审批人员信息
            flowTask.setCreateTime(histTask.getCreateTime());
            flowTask.setFinishTime(histTask.getEndTime());
            flowTask.setDuration(DateUtil.formatBetween(histTask.getDurationInMillis(), BetweenFormatter.Level.SECOND));
            flowTask.setProcDefId(histTask.getProcessDefinitionId());
            flowTask.setTaskDefKey(histTask.getTaskDefinitionKey());
            flowTask.setTaskName(histTask.getName());
            // 流程定义信息
            ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
                    .processDefinitionId(histTask.getProcessDefinitionId()).singleResult();
            flowTask.setDeployId(pd.getDeploymentId());
            flowTask.setProcDefName(pd.getName());
            flowTask.setProcDefVersion(pd.getVersion());
            flowTask.setProcInsId(histTask.getProcessInstanceId());
            flowTask.setHisProcInsId(histTask.getProcessInstanceId());
            // 流程发起人信息
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                    .processInstanceId(histTask.getProcessInstanceId()).singleResult();
            Long userId = Long.parseLong(historicProcessInstance.getStartUserId());
            flowTask.setStartUserId(userId);
            SysUser userInfo = feignSystemService.selectInUserInfo(userId).getData();
            if (userInfo != null) {
                flowTask.setStartUserName(userInfo.getNickName());
            }
            // 流程变量
//            flowTask.setProcVars(histTask.getProcessVariables());
            hisTaskList.add(flowTask);
        }
        taskPage.setRecords(hisTaskList);
        return taskPage;
    }

    /**
     * 查询已办任务列表
     */
    @Override
    public List<WfTaskVo> selectFinishedProcessList(ProcessPage procPage) {
        HistoricTaskInstanceQuery taskInstanceQuery = historyService.createHistoricTaskInstanceQuery()
                .includeProcessVariables().finished().taskAssignee(FlowTaskUtils.getUserId())
                .orderByHistoricTaskInstanceEndTime().desc();
        // 构建搜索条件
        ProcessQueryUtils.buildProcessSearch(taskInstanceQuery, procPage);
        List<HistoricTaskInstance> historicTaskInstanceList = taskInstanceQuery.list();
        List<WfTaskVo> hisTaskList = new ArrayList<>();
        for (HistoricTaskInstance histTask : historicTaskInstanceList) {
            WfTaskVo flowTask = new WfTaskVo();
            // 当前流程信息
            flowTask.setTaskId(histTask.getId());
            // 审批人员信息
            flowTask.setCreateTime(histTask.getCreateTime());
            flowTask.setFinishTime(histTask.getEndTime());
            flowTask.setDuration(DateUtil.formatBetween(histTask.getDurationInMillis(), BetweenFormatter.Level.SECOND));
            flowTask.setProcDefId(histTask.getProcessDefinitionId());
            flowTask.setTaskDefKey(histTask.getTaskDefinitionKey());
            flowTask.setTaskName(histTask.getName());
            // 流程定义信息
            ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
                    .processDefinitionId(histTask.getProcessDefinitionId()).singleResult();
            flowTask.setDeployId(pd.getDeploymentId());
            flowTask.setProcDefName(pd.getName());
            flowTask.setProcDefVersion(pd.getVersion());
            flowTask.setProcInsId(histTask.getProcessInstanceId());
            flowTask.setHisProcInsId(histTask.getProcessInstanceId());
            // 流程发起人信息
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                    .processInstanceId(histTask.getProcessInstanceId()).singleResult();
            Long userId = Long.parseLong(historicProcessInstance.getStartUserId());
            flowTask.setStartUserId(userId);
            SysUser userInfo = feignSystemService.selectInUserInfo(userId).getData();
            if (userInfo != null) {
                flowTask.setStartUserName(userInfo.getNickName());
            }
            // 流程变量
//            flowTask.setProcVars(histTask.getProcessVariables());
            hisTaskList.add(flowTask);
        }
        return hisTaskList;
    }

    /**
     * 查询流程部署关联表单信息
     *
     * @param definitionId 流程定义ID
     * @param deployId     部署ID
     */
    @Override
    public WfDeployForm selectFormContent(String definitionId, String deployId) {
        BpmnModel bpmnModel = repositoryService.getBpmnModel(definitionId);
        if (ObjectUtil.isNull(bpmnModel)) {
            throw new CustomException("获取流程模型失败");
        }
        StartEvent startEvent = BpmnModelUtils.getStartEvent(bpmnModel);
        WfDeployForm deployForm = deployFormMapper.selectOne(new LambdaQueryWrapper<WfDeployForm>()
                .eq(WfDeployForm::getDeployId, deployId)
                .eq(WfDeployForm::getFormKey, startEvent.getFormKey())
                .eq(WfDeployForm::getNodeKey, startEvent.getId()));
        if (ObjectUtil.isNull(deployForm)) {
            throw new CustomException("获取流程表单失败");
        }
        return deployForm;
    }

    /**
     * 根据流程定义ID启动流程实例
     */
    @Override
    @Transactional
    public void startProcByDefId(TaskParam taskParam) {
        try {
            ProcessDefinition procDefinition = repositoryService.createProcessDefinitionQuery()
                    .processDefinitionId(taskParam.getProcDefId()).singleResult();
            taskParam.setProcInsId(startProcInstId(procDefinition, taskParam.getVariables()));
        } catch (Exception e) {
            e.printStackTrace();
            throw new CustomException("流程启动错误");
        }
    }

    /**
     * 根据流程标识,启动流程实例
     */
    @Override
    public String startProcByDefKey(TaskParam taskParam) {
        try {
            ProcessDefinition procDefinition = repositoryService.createProcessDefinitionQuery()
                    .processDefinitionKey(taskParam.getProcDefKey()).latestVersion().singleResult();
            return startProcInstId(procDefinition, taskParam.getVariables());
        } catch (Exception e) {
            e.printStackTrace();
            throw new CustomException("流程启动错误");
        }
    }

    /**
     * 删除流程实例
     */
    @Override
    @Transactional
    public void deleteProcessByIds(List<String> instanceIds) {
        // 校验流程是否结束
        long activeInsCount = runtimeService.createProcessInstanceQuery()
                .processInstanceIds(new HashSet<>(instanceIds)).active().count();
        if (activeInsCount > 0) {
            throw new CustomException("不允许删除进行中的流程实例");
        }
        // 删除历史流程实例
        historyService.bulkDeleteHistoricProcessInstances(instanceIds);
    }

    /**
     * 读取xml文件
     *
     * @param procDefId 流程定义ID
     */
    @Override
    public String queryBpmnXmlById(String procDefId) {
        InputStream inputStream = repositoryService.getProcessModel(procDefId);
        try {
            return IoUtil.readUtf8(inputStream);
        } catch (IORuntimeException exception) {
            throw new CustomException("加载xml文件异常");
        }
    }

    /**
     * 流程详情信息
     *
     * @param procInsId 流程实例ID
     * @param taskId    任务ID
     * @return
     */
    @Override
    public WfDetailVo queryProcessDetail(String procInsId, String taskId) {
        WfDetailVo detailVo = new WfDetailVo();
        // 获取流程实例信息
        HistoricProcessInstance historicProcIns = historyService.createHistoricProcessInstanceQuery()
                .processInstanceId(procInsId).includeProcessVariables().singleResult();
        // 获取流程任务信息
        if (StringUtils.isNotBlank(taskId)) {
            HistoricTaskInstance taskIns = historyService.createHistoricTaskInstanceQuery().taskId(taskId)
                    .includeIdentityLinks().includeProcessVariables().includeTaskLocalVariables().singleResult();
            if (taskIns == null) {
                throw new CustomException("没有可办理的任务");
            }
            detailVo.setTaskFormData(currTaskFormData(historicProcIns.getDeploymentId(), taskIns));
        }
        // 获取Bpmn模型信息
        InputStream inputStream = repositoryService.getProcessModel(historicProcIns.getProcessDefinitionId());
        String bpmnXmlStr = StrUtil.utf8Str(IoUtil.readBytes(inputStream, false));
        BpmnModel bpmnModel = BpmnModelUtils.getBpmnModel(bpmnXmlStr);
        detailVo.setBpmnXml(bpmnXmlStr);
        detailVo.setHistoryProcNodeList(historyProcNodeList(historicProcIns));
        detailVo.setProcessFormList(processFormList(bpmnModel, historicProcIns));
        detailVo.setFlowViewer(getFlowViewer(bpmnModel, procInsId));
        return detailVo;
    }

    /**
     * 启动流程实例
     */
    private String startProcInstId(ProcessDefinition procDefinition, Map<String, Object> variables) {
        if (ObjectUtil.isNotNull(procDefinition) && procDefinition.isSuspended()) {
            throw new CustomException("流程已被挂起,请先激活流程");
        }
        // 设置流程发起人Id到流程中
        String userIdStr = FlowTaskUtils.getUserId();
        identityService.setAuthenticatedUserId(userIdStr);
        variables.put(BpmnXMLConstants.ATTRIBUTE_EVENT_START_INITIATOR, userIdStr);
        // 设置流程状态为进行中
        variables.put(ProcessConstants.PROCESS_STATUS_KEY, ProcessStatus.RUNNING.getStatus());
        // 发起流程实例
        ProcessInstance procInstance = runtimeService.startProcessInstanceById(procDefinition.getId(), variables);
        // 获取流程实例ID,设置表单对象主键值
        variables.put(FlowTaskConstants.ENTITY_ID_CODE, procInstance.getProcessInstanceId());
        // 第一个用户任务为发起人,则自动完成任务
        wfTaskService.startFirstTask(procInstance, variables);
        return procInstance.getProcessInstanceId();
    }

    /**
     * 获取流程变量
     *
     * @param taskId 任务ID
     * @return 流程变量
     */
    private Map<String, Object> getProcessVariables(String taskId) {
        HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery()
                .includeProcessVariables().finished().taskId(taskId).singleResult();
        if (Objects.nonNull(historicTaskInstance)) {
            return historicTaskInstance.getProcessVariables();
        }
        return taskService.getVariables(taskId);
    }

    /**
     * 获取当前任务流程表单信息
     */
    private WfDeployForm currTaskFormData(String deployId, HistoricTaskInstance taskIns) {
        WfDeployForm deployForm = deployFormMapper.selectOne(new LambdaQueryWrapper<WfDeployForm>()
                .eq(WfDeployForm::getDeployId, deployId)
                .eq(WfDeployForm::getFormKey, taskIns.getFormKey())
                .eq(WfDeployForm::getNodeKey, taskIns.getTaskDefinitionKey()));
        if (ObjectUtil.isNotEmpty(deployForm)) {
            return deployForm;
        }
        return null;
    }

    /**
     * 获取历史流程表单信息
     */
    private List<WfDeployForm> processFormList(BpmnModel bpmnModel, HistoricProcessInstance historicProcIns) {
        List<WfDeployForm> procFormList = new ArrayList<>();
        List<HistoricActivityInstance> activityInstanceList = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(historicProcIns.getId()).finished()
                .activityTypes(CollUtil.newHashSet(BpmnXMLConstants.ELEMENT_EVENT_START, BpmnXMLConstants.ELEMENT_TASK_USER))
                .orderByHistoricActivityInstanceStartTime().asc().list();
        List<String> processFormKeys = new ArrayList<>();
        for (HistoricActivityInstance activityInstance : activityInstanceList) {
            // 获取当前节点流程元素信息
            FlowElement flowElement = BpmnModelUtils.getFlowElementById(bpmnModel, activityInstance.getActivityId());
            // 获取当前节点表单Key
            String formKey = BpmnModelUtils.getFormKey(flowElement);
            if (formKey == null) {
                continue;
            }
            boolean localScope = Convert.toBool(BpmnModelUtils.getElementAttributeValue(flowElement,
                    ProcessConstants.PROCESS_FORM_LOCAL_SCOPE), false);
            Map<String, Object> variables = null;
            if (localScope) {
                // 查询任务节点参数,并转换成Map
                variables = historyService.createHistoricVariableInstanceQuery()
                        .processInstanceId(historicProcIns.getId()).taskId(activityInstance.getTaskId())
                        .list().stream().collect(Collectors.toMap(HistoricVariableInstance::getVariableName,
                                HistoricVariableInstance::getValue));
            } else {
                if (processFormKeys.contains(formKey)) {
                    continue;
                }
                variables = historicProcIns.getProcessVariables();
                processFormKeys.add(formKey);
            }
            // 非节点表单此处查询结果可能有多条,只获取第一条信息
            List<WfDeployForm> wfDeployForms = deployFormMapper.selectList(new LambdaQueryWrapper<WfDeployForm>()
                    .eq(WfDeployForm::getDeployId, historicProcIns.getDeploymentId())
                    .eq(WfDeployForm::getFormKey, formKey)
                    .eq(localScope, WfDeployForm::getNodeKey, flowElement.getId()));
            // 过滤避免空集合导致的NULL空指针
            WfDeployForm deployForm = wfDeployForms.stream().findFirst().orElse(null);
            if (ObjectUtil.isNotNull(deployForm)) {
                deployForm.setObjectValue(variables.get(flowElement.getId()));
                procFormList.add(deployForm);
            }
        }
        return procFormList;
    }

    /**
     * 获取历史任务信息列表
     */
    private List<WfProcNodeVo> historyProcNodeList(HistoricProcessInstance historicProcIns) {
        String procInsId = historicProcIns.getId();
        List<HistoricActivityInstance> historicActivityInstanceList = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(procInsId)
                .activityTypes(CollUtil.newHashSet(BpmnXMLConstants.ELEMENT_EVENT_START,
                        BpmnXMLConstants.ELEMENT_EVENT_END, BpmnXMLConstants.ELEMENT_TASK_USER))
                .orderByHistoricActivityInstanceStartTime().desc()
                .orderByHistoricActivityInstanceEndTime().desc().list();
        List<Comment> commentList = taskService.getProcessInstanceComments(procInsId);
        List<WfProcNodeVo> elementVoList = new ArrayList<>();
        for (HistoricActivityInstance activityInstance : historicActivityInstanceList) {
            WfProcNodeVo elementVo = new WfProcNodeVo();
            elementVo.setProcDefId(activityInstance.getProcessDefinitionId());
            elementVo.setActivityId(activityInstance.getActivityId());
            elementVo.setActivityName(activityInstance.getActivityName());
            elementVo.setActivityType(activityInstance.getActivityType());
            elementVo.setCreateTime(activityInstance.getStartTime());
            elementVo.setEndTime(activityInstance.getEndTime());
            if (ObjectUtil.isNotNull(activityInstance.getDurationInMillis())) {
                elementVo.setDuration(DateUtil.formatBetween(activityInstance.getDurationInMillis(), BetweenFormatter.Level.SECOND));
            }
            if (BpmnXMLConstants.ELEMENT_EVENT_START.equals(activityInstance.getActivityType())) {
                if (ObjectUtil.isNotNull(historicProcIns)) {
                    Long userId = Long.parseLong(historicProcIns.getStartUserId());
                    elementVo.setAssigneeId(userId);
                    SysUser userInfo = feignSystemService.selectInUserInfo(userId).getData();
                    if (userInfo != null) {
                        elementVo.setAssigneeName(userInfo.getNickName());
                    }
                }
            } else if (BpmnXMLConstants.ELEMENT_TASK_USER.equals(activityInstance.getActivityType())) {
                if (StringUtils.isNotBlank(activityInstance.getAssignee())) {
                    Long userId = Long.parseLong(activityInstance.getAssignee());
                    elementVo.setAssigneeId(userId);
                    SysUser userInfo = feignSystemService.selectInUserInfo(userId).getData();
                    if (userInfo != null) {
                        elementVo.setAssigneeName(userInfo.getNickName());
                    }
                }
                // 展示审批人员
                List<HistoricIdentityLink> linksForTask = historyService.getHistoricIdentityLinksForTask(activityInstance.getTaskId());
                StringBuilder stringBuilder = new StringBuilder();
                for (HistoricIdentityLink identityLink : linksForTask) {
                    if ("candidate".equals(identityLink.getType())) {
                        if (StringUtils.isNotBlank(identityLink.getUserId())) {
                            Long userId = Long.parseLong(identityLink.getUserId());
                            SysUser userInfo = feignSystemService.selectInUserInfo(userId).getData();
                            if (userInfo != null) {
                                stringBuilder.append(userInfo.getNickName()).append(",");
                            }
                        }
                        if (StringUtils.isNotBlank(identityLink.getGroupId())) {
                            if (identityLink.getGroupId().startsWith(FlowTaskConstants.ROLE_GROUP_PREFIX)) {
                                Long roleId = Long.parseLong(StringUtils.stripStart(identityLink.getGroupId(), FlowTaskConstants.ROLE_GROUP_PREFIX));
                                SysRole roleInfo = feignSystemService.getInRoleInfo(roleId).getData();
                                if (roleInfo != null) {
                                    stringBuilder.append(roleInfo.getRoleName()).append(",");
                                }
                            } else if (identityLink.getGroupId().startsWith(FlowTaskConstants.DEPT_GROUP_PREFIX)) {
                                Long deptId = Long.parseLong(StringUtils.stripStart(identityLink.getGroupId(), FlowTaskConstants.DEPT_GROUP_PREFIX));
                                SysDept deptInfo = feignSystemService.getInDeptByDeptId(deptId).getData();
                                if (deptInfo != null) {
                                    stringBuilder.append(deptInfo.getDeptName()).append(",");
                                }
                            }
                        }
                    }
                }
                if (StringUtils.isNotBlank(stringBuilder)) {
                    elementVo.setCandidate(stringBuilder.substring(0, stringBuilder.length() - 1));
                }
                // 获取意见评论内容
                if (CollUtil.isNotEmpty(commentList)) {
                    List<Comment> comments = new ArrayList<>();
                    for (Comment comment : commentList) {
                        if (comment.getTaskId().equals(activityInstance.getTaskId())) {
                            comments.add(comment);
                        }
                    }
                    elementVo.setCommentList(comments);
                }
            }
            elementVoList.add(elementVo);
        }
        return elementVoList;
    }

    /**
     * 获取流程执行过程
     *
     * @param procInsId
     * @return
     */
    private WfViewVo getFlowViewer(BpmnModel bpmnModel, String procInsId) {
        // 构建查询条件
        HistoricActivityInstanceQuery histActivityInstQuery = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(procInsId);
        List<HistoricActivityInstance> allActivityInstanceList = histActivityInstQuery.list();
        if (CollUtil.isEmpty(allActivityInstanceList)) {
            return new WfViewVo();
        }
        // 查询所有已完成的元素
        List<HistoricActivityInstance> finishedElementList = allActivityInstanceList.stream()
                .filter(item -> ObjectUtil.isNotNull(item.getEndTime())).collect(Collectors.toList());
        // 所有已完成的连线
        Set<String> finishedSequenceFlowSet = new HashSet<>();
        // 所有已完成的任务节点
        Set<String> finishedTaskSet = new HashSet<>();
        finishedElementList.forEach(item -> {
            if (BpmnXMLConstants.ELEMENT_SEQUENCE_FLOW.equals(item.getActivityType())) {
                finishedSequenceFlowSet.add(item.getActivityId());
            } else {
                finishedTaskSet.add(item.getActivityId());
            }
        });
        // 查询所有未结束的节点
        Set<String> unfinishedTaskSet = allActivityInstanceList.stream()
                .filter(item -> ObjectUtil.isNull(item.getEndTime()))
                .map(HistoricActivityInstance::getActivityId).collect(Collectors.toSet());
        // DFS 查询未通过的元素集合
        Set<String> rejectedSet = FlowableUtils.dfsFindRejects(bpmnModel,
                unfinishedTaskSet, finishedSequenceFlowSet, finishedTaskSet);
        return new WfViewVo(finishedTaskSet, finishedSequenceFlowSet, unfinishedTaskSet, rejectedSet);
    }

}
